package com.gopay.cashier.web.controller.T00100;

import com.gopay.cashier.common.exception.WebException;
import com.gopay.cashier.domain.bean.LoginUser;
import com.gopay.cashier.domain.bean.PayChannelDtlBean;
import com.gopay.cashier.domain.bean.PayChannelWayBean;
import com.gopay.cashier.service.riskcontrol.CallRiskControlService;
import com.gopay.cashier.web.command.BankPayWay;
import com.gopay.cashier.web.command.ExpressPayChannelCommand;
import com.gopay.cashier.web.command.ExpressPoundageVo;
import com.gopay.cashier.web.controller.BaseController;
import com.gopay.cashier.web.utils.CashierConfig;
import com.gopay.cashier.web.utils.RSAUtil4js;
import com.gopay.common.cipher.utils.LoggerMaskUtils;
import com.gopay.common.constants.SubAccountConstants;
import com.gopay.common.constants.bank.BisBankBusinessProd;
import com.gopay.common.constants.bank.ExPayBankConstants;
import com.gopay.common.constants.cust.CustPersonInfoConstants;
import com.gopay.common.constants.cust.RealNameCertifyStep;
import com.gopay.common.constants.cust.UserInfoConstants;
import com.gopay.common.constants.cust.UserSource;
import com.gopay.common.constants.ep.EpBindState;
import com.gopay.common.constants.ep.EpCardType;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.constants.trans.*;
import com.gopay.common.core.dic.dao.DicGopayBankInfoQueryDAO;
import com.gopay.common.cps.dao.order.CpsGeneralReceiptOrderQueryDAO;
import com.gopay.common.domain.UserInfo;
import com.gopay.common.domain.bank.PayRequest;
import com.gopay.common.domain.bis.BisBankInfoMain;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.domain.cps.CpsGenReceiptOrder;
import com.gopay.common.domain.cust.CustPersonInfo;
import com.gopay.common.domain.dic.DicGopayBankInfo;
import com.gopay.common.domain.ep.EpCardBindInfo;
import com.gopay.common.domain.pg.PgGenOrderTransDtl;
import com.gopay.common.domain.poundage.PoundageRes;
import com.gopay.common.domain.riskcontrol.RcExpayCardSnapshot;
import com.gopay.common.domain.user.PwdCtrlAttrInfo;
import com.gopay.common.exception.CPSException;
import com.gopay.common.exception.GopayException;
import com.gopay.common.riskcontrol.dao.RcExpayCardSnapshotDAO;
import com.gopay.common.security.encryptiondecryption.SecurityUtil;
import com.gopay.common.user.manager.PwdCtrlAttrInfoManager;
import com.gopay.common.util.DateUtils;
import com.gopay.common.util.HexToBytes;
import com.gopay.common.util.JsonUtils;
import com.gopay.common.util.RequestUtils;
import com.gopay.remote.bank.BisBaseExPayInterfaceRemoteService;
import com.gopay.remote.bank.BisCertificationRemoteService;
import com.gopay.remote.bank.ExPayInteractRemoteService;
import com.gopay.remote.cps.expresspay.EpBankCardRemoteService;
import com.gopay.remote.matcher.BankCodeQueryRemoteService;
import com.gopay.remote.matcher.vo.GopayBankInfoVO;
import com.gopay.remote.order.ReceiptOrderUpdateRemoteService;
import com.gopay.remote.solution.vo.PayChannelDtlInfo;
import ocx.AESWithJCE;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.security.interfaces.RSAPublicKey;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by HJY on 2015/5/12.
 */
@Controller
public class ExpressBaseController extends BaseController {

    @Resource(name = "epBankCardService")
    protected EpBankCardRemoteService epBankCardService;

    @Resource(name = "exAuthRemoteService")
    protected ExPayInteractRemoteService exAuthRemoteService;

    @Resource(name = "exPayRemoteService")
    protected BisBaseExPayInterfaceRemoteService exPayRemoteService;

    @Resource(name = "receiptOrderUpdateService")
    protected ReceiptOrderUpdateRemoteService receiptOrderUpdateService;

    @Resource(name = "bisCertificationRemoteService")
    protected BisCertificationRemoteService bisCertificationRemoteService;

    @Resource(name="callRiskControlService")
    private CallRiskControlService callRiskControlService;

    @Resource(name = "epBankCardService")
    private EpBankCardRemoteService epBankCardRemoteService;

    @Resource(name = "dicGopayBankInfoQueryDAO")
    private DicGopayBankInfoQueryDAO dicGopayBankInfoQueryDAO;

    @Resource(name = "bankCodeQueryClient")
    private BankCodeQueryRemoteService bankCodeQueryRemoteService;

    @Resource(name = "rcExpayCardSnapshotDAO")
    private RcExpayCardSnapshotDAO rcExpayCardSnapshotDAO;

    @Autowired
    private PwdCtrlAttrInfoManager pwdCtrlAttrInfoManager;

    @Autowired
    private CpsGeneralReceiptOrderQueryDAO cpsGeneralReceiptOrderQueryDAO;
    
    protected static final String PORTAL_URL = CashierConfig.get(CashierConfig.PORTAL_URL);
    protected static final String CAS_URL = CashierConfig.get(CashierConfig.CAS_SERVER_URL);

    protected String decrypt4js(String result) throws Exception {

        if (StringUtils.isBlank(result)) {
            return result;
        }

        //根据长度判定是否要解密  100个长度  临时方案  后期最好云账户快捷也加密
        if (result.length() < 100) {
            logger.info("长度小于100 ， 不做解密处理.. ");
            return result;
        }
        byte[] en_result = HexToBytes.HexString2Bytes(result);
        byte[] de_result = RSAUtil4js.decrypt(RSAUtil4js.getKeyPair().getPrivate(),en_result);
        StringBuffer sb = new StringBuffer();
        sb.append(new String(de_result)); 
        return URLDecoder.decode(sb.reverse().toString(), "UTF-8");
    }

    private void decrypt4jsException(ExpressPayChannelCommand exCommand) throws Exception {
        if(exCommand == null){
            return ;
        }
        exCommand.setExCvn2(decrypt4js(exCommand.getExCvn2()));
        exCommand.setExValidDate(decrypt4js(exCommand.getExValidDate()));
        exCommand.setExHolder(decrypt4js(exCommand.getExHolder()));
        exCommand.setExIdCardNo(decrypt4js(exCommand.getExIdCardNo()));
        exCommand.setExMobileNo(decrypt4js(exCommand.getExMobileNo()));
        exCommand.setBankCardNo(decrypt4js(exCommand.getBankCardNo()));
    }

    protected void decrypt4js(ExpressPayChannelCommand exCommand) throws GopayException {
        try {
            decrypt4jsException(exCommand);
        } catch (Exception e) {
            throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002);
        }
    }

    protected PayRequest getPayRequest(String orderId,ExpressPayChannelCommand command) throws GopayException {
        CpsGenMainOrder order = getMainOrder(orderId, true);
        PayRequest base = new PayRequest();
        base.setBank(order.getOutStlmId());
        base.setOrderId(orderId);
        base.setBankBusProd(BisBankBusinessProd._15.value);
        base.setPhoneNo(command.getExMobileNo());
        base.setCardNo(command.getBankCardNo());
        base.setCardHolder(command.getExHolder());
        base.setCidNo(command.getExIdCardNo());
        base.setCidType(CustPersonInfoConstants.CERT_TYPE_IDCARD);
        //add by wjq at 20170907
        base.setValidateCode(command.getExSmsCode());
        if(StringUtils.equals(order.getPayChannel(), PayChannel._06.toString())){
            base.setCvv2(command.getExCvn2());
            base.setAvailableDate(command.getExValidDate());
            base.setBankBusProd(BisBankBusinessProd._05.value);
        }
        try{
            PayRequest log = new PayRequest();
            BeanUtils.copyProperties(log,base);
            if(StringUtils.equals(order.getPayChannel(), PayChannel._06.toString()))
                log.setCvv2("****");
            /**
             * modified by zyt ，对敏感字段的日志做掩码处理
             * 2017-1-12
             */
            logger.info("exPayRequest orderId :"+orderId+" Info:"+ LoggerMaskUtils.maskString(ReflectionToStringBuilder.toStringExclude(log,"availableDate","cvv2","validateCode")));
            //logger.info("exPayRequest orderId :"+orderId+" Info:"+ JsonUtils.toJson(log));
        }catch (Exception e){ }

        base.setBrowser(ExPayBankConstants.VAL_BROWSER_VERSION_NUMBER);
        base.setIp(RequestUtils.getRemoteRealIpAddr(getRequest()));
        base.setTermination(ExPayBankConstants.TERMINAL_TYPE_PC);
        //==start增加结算金额参数 add by liuyong 20170110
        ExpressPoundageVo epv = getPoundageRes(order,command);
        PoundageRes p = epv.getPoundageRes();
        base.setSettleAmt(p.getSettleAmt().toPlainString());
        //==end
        return  base;
    }

    protected ExpressPayChannelCommand getExCommand(ExpressPayChannelCommand command,EpCardBindInfo info){
        if(info == null)
            return  command;

        PayChannel cardPaych = info.getBankAcctType() == EpCardType.CREDIT ? PayChannel._06 :PayChannel._03;
        if(cardPaych == PayChannel._06){
           /* String date = DateUtils.format(info.getCreditCardExpired(), "MMyy");
            command.setExValidDate(date);*/
            command.setExValidDate(info.getCreditCardExpired());
        }

        command.setExMobileNo(info.getBindMobile());
        command.setBankCardNo(info.getBankAcctNum());
        command.setExHolder(info.getBankAcctName());
        command.setExIdCardNo(info.getCertNo());
        command.setExPayChannel(cardPaych.value);
        return command;
    }


    protected   String getHiddenCardNo(String cardNo){
        if(cardNo == null || cardNo.length()<9)
            return "";
        int certNoLen = cardNo.length();
        String pass = "";
        for(int i=0;i<certNoLen-8;i++){
            pass = pass.concat("*");
        }
        return cardNo.substring(0,4).concat(pass).concat(cardNo.substring(certNoLen-4,certNoLen));
    }

    protected  String getHiddenMobileNo(String mobileNo){
        if(mobileNo == null || mobileNo.length()<11)
            return "";
        int certNoLen = mobileNo.length();
        String pass = "";
        for(int i=0;i<4;i++){
            pass = pass.concat("*");
        }
        return mobileNo.substring(0,3).concat(pass).concat(mobileNo.substring(certNoLen-4,certNoLen));
    }
    protected String getHiddenExIdCardNo(String exIdCardNo){
    	 if(exIdCardNo == null || exIdCardNo.length() < 15) // 18->15 add by dongdh 20160324
             return "";
         int certNoLen = exIdCardNo.length();
         String pass = "";
         for(int i=0;i<8;i++){
             pass = pass.concat("*");
         }
         return exIdCardNo.substring(0,6).concat(pass).concat(exIdCardNo.substring(certNoLen-4,certNoLen));
    	
    }
    
    protected String getHiddenExHolder(String holder){
   	 if(holder == null)
            return "";
        int certNoLen = holder.length();
        //如果长度为 2或者3， 则只显示最后一个字， 如果大于3个则显示最后两个字符
        if (certNoLen == 2 || certNoLen == 3) {
        	return StringUtils.leftPad(holder.substring(certNoLen - 1), certNoLen, "*");
        } else if (certNoLen > 3) {
        	return StringUtils.leftPad(holder.substring(certNoLen - 2), certNoLen, "*");
        }
        return holder;
   	
   }
    
    protected EpCardBindInfo createEpCardBindInfo(ExpressPayChannelCommand exCommand,String custId){
        EpCardBindInfo bindInfo = new EpCardBindInfo();
        EpCardType epCardType = StringUtils.equals(exCommand.getExPayChannel(), PayChannel._06.toString()) ? EpCardType.CREDIT : EpCardType.DEBIT;
        bindInfo.setCustId(custId);
        bindInfo.setBindMobile(exCommand.getExMobileNo());
        bindInfo.setCertType(CustPersonInfoConstants.CERT_TYPE_IDCARD);
        bindInfo.setCertNo(exCommand.getExIdCardNo());
        bindInfo.setBankAcctName(exCommand.getExHolder());
        bindInfo.setBankAcctNum(exCommand.getBankCardNo());
        bindInfo.setBankAcctType(epCardType);
        bindInfo.setBankCode(exCommand.getExPayBankCode());
        bindInfo.setBindState(EpBindState.TEMP);
        if(StringUtils.equals(exCommand.getExPayChannel(), PayChannel._06.toString())){
            String vd = exCommand.getExValidDate();
//            String month = vd.substring(0,2);
//            String year = vd.substring(2,4);
           // bindInfo.setCreditCardExpired(DateUtils.strToDate("20".concat(year + "").concat(month), "yyyyMM"));
            bindInfo.setCreditCardExpired(vd);
        }
        bindInfo.setBindTime(new Date());
        bindInfo = epBankCardService.bindEpCardInfo(bindInfo);
        return bindInfo;
    }


    @RequestMapping(value = "/00100/express/progress.shtml")
    public ModelAndView expreeProgress(String orderId,String inOrderId,String t) throws WebException {
        ModelAndView mv = new ModelAndView("/00100/common/progress");
        CpsGenMainOrder order = getMainOrder(orderId, true);
        if (null == order) {
            logger.error("找不到订单！order not exits!" + orderId);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5041);
        }
        if (TxnStaCode.TXN_STA_CD_30000.value == (order.getTxnStaCd())) {
            logger.error("订单状态不对！txn_sta_cd wrong!" + orderId);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5042);
        }
        String result = (TxnStaCode.TXN_STA_CD_20000.value == order.getTxnStaCd())?"1":"0";
        mv.addObject("orderId",orderId);
        StringBuffer sb = new StringBuffer();
        sb.append("/00100/express/result.shtml?orderKey="+getRequest().getParameter("orderKey")+"&t="+t+"&orderId="+orderId);
        if(StringUtils.isNotBlank(inOrderId))
            sb.append("&inOrderId="+inOrderId);
        mv.addObject("redirectUrl",sb.toString());
        mv.addObject("result",result);
        return  mv;
    }

    @RequestMapping(value = "/00100/express/result.shtml")
    public ModelAndView expressResult(String orderId,String inOrderId,String t) throws WebException {
        CpsGenMainOrder order = cpsGeneralMainOrderQueryDAO.find(CpsGenMainOrder.class,orderId);
        if(order == null)
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5041);

        if (TxnStaCode.TXN_STA_CD_30000.value == (order.getTxnStaCd())) {
            logger.error("订单状态不对！txn_sta_cd wrong!" + orderId);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5042);
        }
        ModelAndView mv = new ModelAndView();
        mv.addObject("portalUrl",PORTAL_URL);
        if(TxnStaCode.TXN_STA_CD_20000.value == order.getTxnStaCd()){
            boolean isFirst = false;
            if(StringUtils.isNotBlank(t) && !StringUtils.equals(t,"0")){
                EpCardBindInfo bindInfo = epBankCardService.getCardInfoById(t);
                if(bindInfo != null){
                    CustPersonInfo custInfo =  custPersonInfoQueryManager.get(bindInfo.getCustId());
                    getRequest().getSession().setAttribute("fillInfoCustId", custInfo.getCustId());
                    if(StringUtils.equals(custInfo.getCustStat(), CustPersonInfoConstants.CUST_STAT_NORMAL) && StringUtils.isBlank(custInfo.getPayPwd())){
                        isFirst = true;
                        mv.setViewName("/00100/content/express/firstPayRes");
                        BisBankInfoMain bankInfo = bisBankInfoService.getByCode(bindInfo.getBankCode());
                        String bankName = bankInfo.getBankName();
                        String type = "储蓄卡";
                        String exPayChannel = PayChannel._03.value;
                        if(bindInfo.getBankAcctType() == EpCardType.CREDIT){
                            type = "信用卡";
                            exPayChannel = PayChannel._06.value;
                        }
                        String exPayBankName = bankName.concat(type);
                        mv.addObject("hideExMobileNo",getHiddenMobileNo(bindInfo.getBindMobile()));
                        mv.addObject("exPayBankCode",bindInfo.getBankCode());
                        mv.addObject("exPayChannel",exPayChannel);
                        mv.addObject("exPayBankName",exPayBankName);
                        mv.addObject("hideBankCardNo",getHiddenCardNo(bindInfo.getBankAcctNum()));

                        mv.addObject("custId",bindInfo.getCustId());
                        mv.addObject("orderId",orderId);
                    }
                }
            }
            if(!isFirst)
                mv.setViewName("/00100/common/success");
        }else{
            mv.setViewName("/00100/common/fail");
        }
        mv.addObject("order", getOrderInfo(orderId));
        orderId = StringUtils.isNotBlank(inOrderId) ? inOrderId :orderId;
        mv.addObject("notifyMerUrl","/redirect/BankPayCallbackSelf.shtml?orderKey="+getRequest().getParameter("orderKey")+"&orderId="+orderId);
        logOut();
        return mv;
    }


    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class })
    protected EpCardBindInfo bindCardInfo(ExpressPayChannelCommand exCommand, CpsGenMainOrder order) throws GopayException {
        boolean bind = false;
        EpCardBindInfo bindInfo = null;
        if(StringUtils.isNotBlank(exCommand.getExCardId())){
            //已绑定卡
            return epBankCardService.getCardInfoById(exCommand.getExCardId());
        }

        CustPersonInfo personInfo = getExpressUser(exCommand, order);
        if (personInfo != null ) {
            if (
               (( CustPersonInfoConstants.REAL_NAME_CERTIFY_HALF.equals(personInfo.getIsRealNameCertify())
                    ||CustPersonInfoConstants.REAL_NAME_CERTIFY_YES.equals(personInfo.getIsRealNameCertify())
                ) && StringUtils.equals(personInfo.getCertNo(),exCommand.getExIdCardNo()))
               || (CustPersonInfoConstants.REAL_NAME_CERTIFY_NO.equals(personInfo.getIsRealNameCertify()))){
                bind = true;
            }
        }
        if(bind){
            bindInfo = epBankCardService.getBindCardInfoByCustIdBankNo(personInfo.getCustId(),exCommand.getBankCardNo());
            if(bindInfo == null){
                bindInfo = createEpCardBindInfo(exCommand,personInfo.getCustId());
            }else{
                boolean freeze = epBankCardService.isFreezeCardNo(bindInfo.getBankAcctNum());
                if(freeze){
                	  /**start ---卡号日志掩码处理 ssj 2017-04-18*/
                    logger.error(this.getClass() + LoggerMaskUtils.maskString(bindInfo.getBankAcctNum())+" was freezed " + exCommand);
                   /**end*/
                    throw new WebException(ProcCodeConstants.PROC_CODE_100E5118);
                }

                if(!StringUtils.equals(bindInfo.getBindMobile(),exCommand.getExMobileNo())){
                    bindInfo.setBindMobile(exCommand.getExMobileNo());
                    epBankCardService.updateEpCardBindInfo(bindInfo);
                }
            }
        }
        return bindInfo;
    }


    private CustPersonInfo getExpressUser(ExpressPayChannelCommand command, CpsGenMainOrder order) throws GopayException {
        CustPersonInfo pinfo = null;
        try {
            LoginUser loginUser = getLoginUser();
            if(loginUser != null){
                if (UserType.Person.equals(UserType.get(loginUser.getUser().getUserType()))) {
                    getRequest().getSession().setAttribute("fillInfoCustId", loginUser.getUser().getCustId());
                    return  custPersonInfoQueryManager.get(loginUser.getUser().getCustId());
                }
                return null;//企业用户
            }

            if (allCustInfoQueryDAO.isCustCorpMobile(command.getExMobileNo())) {
                return null;//企业用户
            }

            pinfo = custPersonInfoQueryManager.getByCustMob(command.getExMobileNo());
            if(pinfo != null){
            	  /**start ---卡号日志掩码处理 ssj 2017-04-18*/
                logger.error("createFastUser-->has the same ccf custId :"+pinfo.getCustId()+";custMob:"+LoggerMaskUtils.maskString(pinfo.getCustMob()));
                /**end*/
              
                return pinfo;
            }
            CustPersonInfo personInfo = new CustPersonInfo();
            personInfo.setRegType(CustPersonInfoConstants.REG_TYPE_MOBILE);
            personInfo.setCertNo(command.getExIdCardNo());
            personInfo.setCertType(CustPersonInfoConstants.CERT_TYPE_IDCARD);
            personInfo.setCustMob(command.getExMobileNo());
            personInfo.setCustName(command.getExHolder());
            personInfo.setMobileCertifyTime(new Date());
            personInfo.setLastUpdTs(new Date());
            personInfo.setCreatedTs(new Date());
            personInfo.setCustStat(CustPersonInfoConstants.CUST_STAT_WAIT_EMAIL_CERTIFY);
            personInfo.setIsRealNameCertify(CustPersonInfoConstants.REAL_NAME_CERTIFY_NO);
            personInfo.setIsMobileCertify("1");
            //待补全信息（需补全姓名身份证，职业，支付密码/问题，身份证正反面）  dak.wang  20160524
            personInfo.setRealNameCertifyStep(RealNameCertifyStep.REAL_NAME_CERTIFY_STEP_14.value);
            personInfo.setRegisterIp(RequestUtils.getRemoteRealIpAddr(getRequest()));//增加注册IP，addby songfengli 20160923

            UserInfo userInfo = new UserInfo();
            userInfo.setCreatedTs(new Date());
            userInfo.setOperMobile(command.getExMobileNo());
            userInfo.setOperName(command.getExHolder());
            userInfo.setUserType(UserType.Person.value);
            userInfo.setUserStat(UserInfoConstants.USER_STATE_AWAIT_EMAIL_VERIFY);
            userInfo.setOperId("999");
            userInfo.setLastUpdTs(new Date());
            userInfo.setCreatedTs(new Date());
            userInfo.setRegTime(new Date());
            userInfo.setIspwdQuesLock(UserInfoConstants.PWD_STAT_NORMAL);
            userInfo.setPwdErrNum(0);
            userInfo.setPwdQuesErrNum(0);
            userInfo.setSecuretyLevel(new BigDecimal(UserInfoConstants.SECURETY_LEVEL_PASSWORD));
            userInfo.setIsFirstLogin(UserInfoConstants.FIRST_LOGIN);
            if(GatewaySource.GATEWAY_SOURCE_01.value.equals(order.getGatewaySource())){
                userInfo.setUserSource(UserSource.PC_EXPRESS.value);//插入用户来源,PC
            } else if(GatewaySource.GATEWAY_SOURCE_02.value.equals(order.getGatewaySource())){
                userInfo.setUserSource(UserSource.WAP_EXPRESS.value);//插入用户来源,WAP
            }
            UserInfo newUserInfo = userRemoteService.saveCustPersonUser(personInfo,userInfo);
            getRequest().getSession().setAttribute("fillInfoCustId", newUserInfo.getCustId());
            pinfo = custPersonInfoQueryManager.get(newUserInfo.getCustId());
            logger.info("create new Express User custId:"+pinfo.getCustId() +" for orderId:"+getRequest().getParameter(GOPAY_ORDER_ID));
        } catch (CPSException e) {
            e.printStackTrace();
            throw new GopayException(ProcCodeConstants.PROC_CODE_200E9002);
        }
        return pinfo;
    }

    protected ExpressPoundageVo getPoundageRes(CpsGenMainOrder order,ExpressPayChannelCommand command) throws WebException {
        ExpressPoundageVo vo  = new ExpressPoundageVo();
        LoginUser user = getLoginUser();
        //网关支付 增加特例银行编码  add by jianghoup 20160908
        String bankCode = command.getExPayBankCode();
        logger.info("增加特例银行，编码为："+bankCode);

        if(user == null){
            //未登录，银行卡支付
            if(command.getExPayWay() != BankPayWay.A && command.getExPayChannel() != null){
                PayChannel payChannel = PayChannel.get(command.getExPayChannel());
                vo.setPayChannel(payChannel);
                vo.setPoundageRes(getPoundageRes(order, payChannel,bankCode));
                return vo;
            }
        }else{
            //已登录，先充值后支付，比较手续费
            PayChannel payChannel1 = getPayChannel();
            PoundageRes res1 = getPoundageRes(order, payChannel1,bankCode);
            vo.setPayChannel(payChannel1);
            vo.setPoundageRes(res1);
            if(command.getExPayWay() != BankPayWay.A && command.getExPayChannel() != null){
                PayChannel payChannel2 =  PayChannel.get(command.getExPayChannel());
                PoundageRes res2 = getPoundageRes(order, payChannel2,bankCode);
                int comp = res1.getTotalFeeAmt().compareTo(res2.getTotalFeeAmt());
                if(comp ==-1 || comp ==0 || command.getExPayWay() == BankPayWay.F ){
                    vo.setPayChannel(payChannel2);
                    vo.setPoundageRes(res2);
                }
            }
            return  vo;
        }
        throw new WebException(ProcCodeConstants.PROC_CODE_100E5051);
    }

    protected PayChannel getPayChannel(){
        PayChannel payChannel = null;
        LoginUser loginUser = getLoginUser();
        if(loginUser!=null){
            UserType userType = UserType.get(loginUser.getUser().getUserType());
            if (UserType.Person.equals(userType)) {
                payChannel = PayChannel._02;
            } else {
                payChannel = PayChannel._52;
            }
        }
        return payChannel;
    }

    @Async
    protected void updatePayOrder(String orderId,String cardNo) throws GopayException{
        if (StringUtils.isNotBlank(orderId) && StringUtils.isNotBlank(cardNo)) {
            receiptOrderUpdateService.updateEpBankCardNo(orderId, cardNo);
        } else {
            /**
             * modified by zyt 敏感字段掩码显示
             * 2017-2-9
             */
            logger.error("updatePayOrder is error orderId:" + orderId + ";cardNo:" + LoggerMaskUtils.maskString(cardNo));
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E9204);
        }
    }

    @RequestMapping(value = "/00100/express/timeout.shtml")
    public ModelAndView timeout(String orderId){
        logger.error("orderId:"+orderId+" is timeout!");

        ModelAndView mv = new ModelAndView("/00100/common/timeout");
        CpsGenMainOrder order = cpsGeneralMainOrderQueryDAO.find(CpsGenMainOrder.class,orderId);
        mv.addObject("errCode",order.getErrCode());
        mv.addObject("errMsg",order.getErrMsg());
        return mv;
    }
    
    
    /**
     * 快捷卡支付 身份验证版  校验  update by dongdh 20160319
     * @param transDtl
     * @param exCommand
     */
    protected void validateExpressAuthentication (PgGenOrderTransDtl transDtl,
    		ExpressPayChannelCommand exCommand, boolean isCheckRealNameCertify ) throws GopayException {
    	
    	if (transDtl != null) {
    		if (StringUtils.isNotBlank(transDtl.getBuyerRealBankAcctNum())) {
            	//校验卡号是否一致
            	if (!StringUtils.equals(transDtl.getBuyerRealBankAcctNum(), exCommand.getBankCardNo())) {
            		throw new WebException(ProcCodeConstants.PROC_CODE_100E6084);
            	}
            }

            if (StringUtils.isNotBlank(transDtl.getBuyerRealCertNo()) && 
            		StringUtils.isNotBlank(transDtl.getBuyerRealName())) {
            	//校验提交的 身份信息是否一致
            	
            	if (isCheckRealNameCertify) {
            		checkPayCustRealNameCertify(getLoginUser());
            	}

            	if(!(StringUtils.equals(transDtl.getBuyerRealName(), exCommand.getExHolder())
            		&&StringUtils.equals(transDtl.getBuyerRealCertNo(), exCommand.getExIdCardNo())
                		 )) {
                		throw new WebException(ProcCodeConstants.PROC_CODE_100E6083);
                }
            	// 快捷支付改造修改  update by dhj at 20161201 start
            	/*if(StringUtils.isNotBlank(exCommand.getExIdCardNo6())) {
            		//如果是选择的卡号进行提交的 则页面是输入 身份证后六位 进行校验的
            		String tempNo = transDtl.getBuyerRealCertNo();
            		String idCard = tempNo.substring(tempNo.length() - 6, tempNo.length());
            		
            		if(!StringUtils.equals(exCommand.getExIdCardNo6(),idCard)){
            			//后六位 校验未通过
            			throw new WebException("身份证号后六位错误");
            		}
            		
            	} else {
            		
            	}*/
            	// 快捷支付改造修改  update by dhj at 20161201 end
            }
    	}
    }
    
    /**
     * 快捷支付 提交校验  方案配置.
     * @param exCommand
     * @param order
     * @throws WebException
     */
    protected void checkSolution(ExpressPayChannelCommand exCommand, CpsGenMainOrder order) throws WebException {
    	
    	if(exCommand.getExPayWay() != BankPayWay.A){
    	    /*通用分账  added by Chenyu Li at 2018/3/13 start*/
            PayChannelWayBean payWay;
            if(isSplit(order)){
                payWay = soluBisPayChannelService.getSoluBisPayChannel(order.getGopayIntTxnCd(), order.getOtherAcct());
            }else{
                payWay = soluBisPayChannelService.getSoluBisPayChannel(order.getGopayIntTxnCd(), getAcctId(order));
            }
    	    /*通用分账  added by Chenyu Li at 2018/3/13 end*/
    		//方案清算渠道校验

            String exPayChannel = exCommand.getExPayChannel();
            boolean isCheck = false;
            if (payWay.isSupport(PayChannelType.FAST_PAY.value)) {
            	String bankCode = exCommand.getExPayBankCode();
            	PayChannelDtlBean payChannelDtl = payWay.getPayChannelDtl(PayChannelType.FAST_PAY.value);
            	Map<String, List<PayChannelDtlInfo>> bankCodes = payChannelDtl.getBankCodes();
            	if (bankCodes != null && bankCodes.size() > 0) {
            		List<PayChannelDtlInfo> list = bankCodes.get(exPayChannel);
            		if (list != null && list.size() > 0) {
            			for (PayChannelDtlInfo payChannelDtlInfo : list) {
    						if (StringUtils.equals(payChannelDtlInfo.getOutStlmId(), bankCode)) {
    							isCheck = true;
    							break;
    						}
    					}
            		}
            	}
            }
            
            if (!isCheck) {
            	logger.error("快捷支付方案校验未通过orderId=" + order.getGopayOrderId());
                throw new WebException(ProcCodeConstants.PROC_CODE_100E6085);
            } else {
            	logger.error("快捷支付方案校验通过orderId=" + order.getGopayOrderId());
            }
    		
    	}
    	
    }
    
    /**
     * 生成快捷短信验证码令牌
     * @param orderId
     * @param bankCardNo
     * @throws WebException
     */
    protected void generateEpSmsToken(String orderId,String bankCardNo){
        //生成快捷短信验证码令牌  add by fanghw 20160514
        String epSmsSessionKey=orderId+"_"+bankCardNo;
        getRequest().getSession().setAttribute(epSmsSessionKey, "success");
        /**
         * modified by zyt 打印日志，是用一临时变量，存储输出结果，临时变量的卡号用掩码显示
         * 2017-2-9
         */
        String epSmsSessionKeyTmp=orderId+"_" + LoggerMaskUtils.maskString(bankCardNo);
        logger.info("【快捷支付】Ajax短信校验成功后，生成快捷短信验证码令牌sessionKey="+epSmsSessionKeyTmp);
        
    }
    
    /**
     * 校验快捷短信验证码令牌
     * @param orderId
     * @param bankCardNo
     * @throws WebException
     */
    protected void checkEpSmsToken(String orderId,String bankCardNo) throws WebException{
        //校验快捷短信验证码令牌  add by fanghw 20160514
        String epSmsSessionKey=orderId+"_"+bankCardNo;
        String epSmsSessionValue=(String)getRequest().getSession().getAttribute(epSmsSessionKey);
        getRequest().getSession().removeAttribute(epSmsSessionKey);
        /**
         * modified by zyt 打印日志，是用一临时变量，存储输出结果，临时变量的卡号用掩码显示
         * 2017-2-9
         */
        String epSmsSessionKeyTmp=orderId+"_" + LoggerMaskUtils.maskString(bankCardNo);
        logger.info("【快捷支付】服务端校验快捷短信验证码令牌sessionKey="+ epSmsSessionKeyTmp +",value="+epSmsSessionValue);
        if(!"success".equals(epSmsSessionValue)){
            throw new WebException(ProcCodeConstants.PROC_CODE_100E8005);
        };
    }
    
    public static void main(String[] args) {
    	String exIdCardNo = "123456789012345";
    	if(exIdCardNo == null || exIdCardNo.length()<18)
            System.out.println("-------");
        int certNoLen = exIdCardNo.length();
        String pass = "";
        for(int i=0;i<8;i++){
            pass = pass.concat("*");
        }
        String xxx = exIdCardNo.substring(0,6).concat(pass).concat(exIdCardNo.substring(certNoLen-4,certNoLen));
        System.out.println(xxx);
    }

    /**
     *
     * @param order 主订单对象
     * @param exCommand 快捷支付渠道对象
     * @return 是否跳转提示页面
     * @throws WebException 风控拒绝异常
     */
    protected ModelAndView callRiskControl(CpsGenMainOrder order, ExpressPayChannelCommand exCommand)throws WebException{
        try {
            //未登录个人快捷查询custId
            LoginUser loginUser = getLoginUser();
            String payCustId = null;
            if(loginUser == null || loginUser.getUser() == null || loginUser.getUser().getCustId() == null){
                CustPersonInfo cust = custPersonInfoQueryManager.findByCustMobmobile(exCommand.getExMobileNo());
                if(cust != null){
                    payCustId = cust.getCustId();
                }
            }
            //调用风控
            callRiskControlService.assess(order.getGopayOrderId(), order.getPayChannel(), exCommand.getBankCardNo(), payCustId);
            return null;
        }catch (GopayException ge){
            //非人工审核的都抛出异常
            if(! ProcCodeConstants.PROC_CODE_200G1001.equals(ge.getErrCode())
                    && ! ProcCodeConstants.PROC_CODE_200G3002.equals(ge.getErrCode())){
                //触发风控模型阻断交易跳转到失败页面
                if(ProcCodeConstants.PROC_CODE_200G3001.equals(ge.getErrCode())){
                   return toFailPage(order);
                }else{
                    throw new WebException(ge.getErrCode(), ge);
                }
            }
            //风控拒绝
            //1.信用卡快捷  需要 存储CVN2
            if(PayChannel._06.value.equals(exCommand.getExPayChannel()) || PayChannel._03.value.equals(exCommand.getExPayChannel())){

                if(StringUtils.isNotBlank(exCommand.getExCardId())){
                    EpCardBindInfo cardInfo = epBankCardRemoteService.getCardInfoById(exCommand.getExCardId());
                    exCommand.setExHolder(cardInfo.getBankAcctName());
                    exCommand.setExIdCardNo(cardInfo.getCertNo());
                    exCommand.setExValidDate(cardInfo.getCreditCardExpired());
                }
                //绑定银行卡
                try {
                    bindCardInfo(exCommand, order);
                } catch (GopayException e) {
                    logger.error("绑定银行卡有异常 。。。");
                    throw new WebException("绑定银行卡异常 ! ", e);
                }

                RcExpayCardSnapshot snapshot = new RcExpayCardSnapshot();

                snapshot.setGopayOrderId(order.getGopayOrderId());
                snapshot.setMobile(exCommand.getExMobileNo());
                snapshot.setBankAcctName(exCommand.getExHolder());//cardInfo.getBankAcctName()
                /**
                 * modified by zyt 已经在实体类加密
                 * 2017-1-11
                 */
                snapshot.setCardNo(exCommand.getBankCardNo());
                //snapshot.setCardNo(SecurityUtil.encrypt(exCommand.getBankCardNo()));
                snapshot.setBankCode(exCommand.getExPayBankCode());
                snapshot.setCardType(PayChannel._06.value.equals(exCommand.getExPayChannel()) ? EpCardType.CREDIT.value : EpCardType.DEBIT.value);// cardInfo.getBankAcctType().value
                snapshot.setCertType(CustPersonInfoConstants.CERT_TYPE_IDCARD);//cardInfo.getCertType()
                /**
                 * modified by zyt 已经在实体类加密
                 * 2017-1-11
                 */
                snapshot.setCertNo(exCommand.getExIdCardNo());//cardInfo.getCertNo()
                //snapshot.setCertNo(SecurityUtil.encrypt(exCommand.getExIdCardNo()));//cardInfo.getCertNo()
                snapshot.setCreatedTs(new Date());
                snapshot.setUpdateTs(new Date());

                String bankName = "";
                DicGopayBankInfo bankInfo = dicGopayBankInfoQueryDAO.findByAbbrCode(exCommand.getExPayBankCode());
                if(bankInfo != null) {
                    GopayBankInfoVO bankInfoVO = bankCodeQueryRemoteService.getBankInfoByName(bankInfo.getRawName());
                    bankName = bankInfoVO.getName();
                }
                snapshot.setBankName(bankName);
                if(PayChannel._06.value.equals(exCommand.getExPayChannel())) {
                	/**
                     * modified by zyt 已经在实体类加密
                     * 2017-1-11
                     */
                	//start+++++++++
                	snapshot.setCreditCardExpired(exCommand.getExValidDate());//cardInfo.getCreditCardExpired()
                	snapshot.setRemark1(exCommand.getExCvn2());
                    /*snapshot.setCreditCardExpired(SecurityUtil.encrypt(exCommand.getExValidDate()));//cardInfo.getCreditCardExpired()
                    snapshot.setRemark1(SecurityUtil.encrypt(exCommand.getExCvn2()));*/
                	//end++++++++++++
                }else{
                    snapshot.setCreditCardExpired("");
                    snapshot.setRemark1("");
                }
                rcExpayCardSnapshotDAO.save(snapshot);
            }
            //2.人工审核中。。。
            return toAuditing(order);
        }
    }

    private ModelAndView toAuditing(CpsGenMainOrder order) throws WebException {
        ModelAndView mv = new ModelAndView("/00100/content/express/auditing");
        mv.addObject("order", getOrderInfo(order.getGopayOrderId()));
        mv.addObject("portalUrl",PORTAL_URL);
        return mv;
    }

    private ModelAndView toFailPage(CpsGenMainOrder order) throws WebException{
        ModelAndView mv = new ModelAndView("/00100/content/express/failPage");
        mv.addObject("order", getOrderInfo(order.getGopayOrderId()));
        mv.addObject("portalUrl",PORTAL_URL);
        return mv;
    }

    /**
     * 记录密码控件日志
     * @author <a href="mailto:yhwpeng@126.com">wangdong</a>
     * @date 2017-01-09 15:21:42
     */
    public Integer logMicrodone(HttpServletRequest request,String mcryptKey,String scenceCode,String gopayOrderId,String status,UserInfo user){
        String network=request.getParameter("network");
        String disk=request.getParameter("disk");
        String cpu=request.getParameter("cpu");
        String hardList=request.getParameter("hardList");

        String localNetwork="",localDisk="",localCpu="",localHardList="";
        if (StringUtils.isNotEmpty(mcryptKey)){
            localNetwork= AESWithJCE.getResult(mcryptKey, network);
            localDisk= AESWithJCE.getResult(mcryptKey, disk);
            localCpu= AESWithJCE.getResult(mcryptKey, cpu);
            localHardList= AESWithJCE.getResult(mcryptKey, hardList);
        }

        PwdCtrlAttrInfo info = new PwdCtrlAttrInfo(localCpu,localDisk,localHardList);
        if (user!=null){
            info.setOperSource(scenceCode + user.getUserType());
            info.setUserId(user.getUserId());
            info.setCustId(user.getCustId());
        }else{
            info.setOperSource(scenceCode + "99");//99表示无法获取用户类型，异常类型，需要排查
        }
        info.setGopayOrderId(gopayOrderId);
        info.setNetwork(localNetwork);
        info.setGmtCreate(DateUtils.getCurrDate());
        if (status==null){
            info.setStatus("java.lang.NullPointerException");
        }else{
            info.setStatus(status.length() > 400 ? status.substring(0, 400) : status);
        }
        if (request!=null){
            info.setRealIp(RequestUtils.getRemoteRealIpAddr(request));
        }
        logger.info("保存密码控件操作记录，明细：" + ToStringBuilder.reflectionToString(info));
        return pwdCtrlAttrInfoManager.savePwdCtrlAttrInfo(info);
    }
}
